package com.aqie.rabbit.controller;

import com.aqie.rabbit.access.AccessLimit;
import com.aqie.rabbit.bean.api.base.CodeMsg;
import com.aqie.rabbit.bean.api.base.ResponseModel;
import com.aqie.rabbit.bean.api.group.GroupCreateModel;
import com.aqie.rabbit.bean.api.group.GroupMemberAddModel;
import com.aqie.rabbit.bean.api.group.GroupMemberUpdateModel;
import com.aqie.rabbit.bean.card.ApplyCard;
import com.aqie.rabbit.bean.card.GroupCard;
import com.aqie.rabbit.bean.card.GroupMemberCard;
import com.aqie.rabbit.bean.db.Group;
import com.aqie.rabbit.bean.db.GroupMember;
import com.aqie.rabbit.bean.db.User;
import com.aqie.rabbit.provider.LocalDateTimeConverter;
import com.aqie.rabbit.service.IGroupMemberService;
import com.aqie.rabbit.service.IGroupService;
import com.aqie.rabbit.service.IPushService;
import com.aqie.rabbit.service.IUserService;
import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotBlank;
import javax.ws.rs.DefaultValue;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/group")
public class GroupController {
    @Autowired
    private IUserService userService;
    @Autowired
    private IGroupService groupService;

    @Autowired
    private IGroupMemberService groupMemberService;

    @Autowired
    private IPushService pushService;

    /**
     * 创建群
     * @param model
     * @return
     */
    @PostMapping
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<GroupCard> create(@RequestBody @Validated GroupCreateModel model){
        if (!GroupCreateModel.check(model)) {
            return ResponseModel.error(CodeMsg.GROUP_CREATE_MEMBER_LIST_EMPTY_ERROR);
        }
        // 获取当前登录用户 即 创建者
        User creator = userService.getUser();
        // 创建者不在列表中
        model.getUsers().remove(creator.getId());
        if (model.getUsers().size() == 0){
            return ResponseModel.error(CodeMsg.GROUP_CREATE_MEMBER_LESS_THAN_TWO_ERROR);
        }
        // 检测群名是否存在
        if (groupService.findByName(model.getName()) != null){
            return ResponseModel.error(CodeMsg.GROUP_NAME_EXIT_ERROR);
        }

        // Set<String> users 存储的用户id
        List<User> users = new ArrayList<>();
        for (String s : model.getUsers()){
            User user = userService.findById(s);
            if (user == null){
                continue;
            }
            users.add(user);
        }
        // 没有一个成员
        if (users.size() == 0){
            return ResponseModel.error(CodeMsg.GROUP_CREATE_MEMBER_LESS_THAN_TWO_ERROR);
        }

        Group group = groupService.create(creator, model, users);
        if (group == null){
            return ResponseModel.error(CodeMsg.CREATE_GROUP_ERROR);
        }

        // 获取管理员(登录者)信息
        GroupMember creatorMember = groupMemberService.getMember(creator, group.getId());
        if (creatorMember == null){
            return ResponseModel.error(CodeMsg.GET_GROUP_CREATOR_ERROR);
        }

        // 拿到群的成员，给所有的群成员发送信息，已经被添加到群的信息
        Set<GroupMember> members = groupMemberService.getMembers(group);
        if (members == null){
            return ResponseModel.error(CodeMsg.GROUP_MEMBER_LIST_EMPTY_ERROR);
        }
        // 排除自己
        members = members.stream()
                .filter(groupMember -> !groupMember.getId().equalsIgnoreCase(creatorMember.getId()))
                .collect(Collectors.toSet());
        // 开始发起推送
        pushService.pushJoinGroup(members);
        return ResponseModel.success(new GroupCard(creatorMember));
    }

    /**
     * like 模糊搜索群(没有传递参数就是搜索最近所有的群)
     * 搜索 (必须加/search,不然会匹配到 {groupId})
     * @param name 可为空
     * @return
     */
    @GetMapping(value = {"/search/{name}","/search"})
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<List<GroupCard>> search(@DefaultValue("") @PathVariable(value = "name", required = false)  String name){
        User self = userService.getUser();
        List<Group> groups = groupService.search(name);

        /**
         * 判断我有没有加入群
         * 找一个群内所有成员 | 查询一个人所有群
         */
        if (groups != null && groups.size() > 0){
            List<GroupCard> groupCards = groups.stream()
                    .map(group -> {
                        GroupMember member = groupMemberService.getMember(self, group.getId());
                        return new GroupCard(group, member);
                    }).collect(Collectors.toList());
            return ResponseModel.success(groupCards);
        }
        return ResponseModel.success();
    }

    /**
     * 拉取自己当前的群的列表
     * 必须加上required false
     * @param dateStr 时间字段，不传递，则返回全部当前的群列表；有时间，则返回这个时间之后的加入的群
     * @return 群信息列表
     */
    @GetMapping(value = {"/list","/list/{date:(?:.*)?}"})
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<List<GroupCard>> list(@DefaultValue("") @PathVariable(value = "date",required = false) String dateStr){
        User self = userService.getUser();
        LocalDateTime dateTime = null;
        if (!Strings.isNullOrEmpty(dateStr)) {
            try {
                dateTime = LocalDateTime.parse(dateStr, LocalDateTimeConverter.FORMATTER);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }

        // 获取一个人加入的所有群
        Set<GroupMember> members = groupMemberService.getMembers(self);
        if (members == null || members.size() == 0){
            return ResponseModel.success();
        }

        final LocalDateTime finalDateTime = dateTime;
        List<GroupCard> groupCards = members.stream()
                .filter(groupMember -> finalDateTime == null // 时间如果为null则不做限制
                        || groupMember.getUpdateAt().isAfter(finalDateTime) // 时间不为null,你需要在我的这个时间之后
                )
                .map(GroupCard::new) // 转换操作
                .collect(Collectors.toList());
        return ResponseModel.success(groupCards);
    }

    /**
     * 根据群id 获取自己加入一个群信息
     * @param groupId 群id
     * @return 群信息
     */
    @GetMapping("/{groupId}")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<GroupCard> getGroup(@NotBlank @PathVariable("groupId") String groupId){
        User self = userService.getUser();
        GroupMember member = groupMemberService.getMember(self, groupId);
        if (member == null){
            return ResponseModel.error(CodeMsg.GROUP_MEMBER_NOT_FOUND_ERROR);
        }
        return ResponseModel.success(new GroupCard(member));
    }

    /**
     * 根据群id 获取自己加入群内所有成员信息
     * @param groupId 群id
     * @return 群成员列表
     */
    @GetMapping("/{groupId}/member")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<List<GroupMemberCard>> members(@NotBlank @PathVariable("groupId") String groupId){
        User user = userService.getUser();
        // 判断群是否存在
        Group group = groupService.findById(groupId);
        if (group == null){
            return ResponseModel.error(CodeMsg.GROUP_NOT_FOUND_ERROR);
        }
        // 判断是否在群组内
        GroupMember member = groupMemberService.getMember(user, groupId);
        if (member == null){
            return ResponseModel.error(CodeMsg.GROUP_NOT_JOIN_ERROR);
        }

        // 根据群 获取群组所有成员(不重复集合)
        Set<GroupMember> members = groupMemberService.getMembers(group);
        if (members == null){
            return ResponseModel.error(CodeMsg.GET_GROUP_MEMBER_ERROR);
        }
        List<GroupMemberCard> memberCards = members
                .stream()
                .map(GroupMemberCard::new)
                .collect(Collectors.toList());
        return  ResponseModel.success(memberCards);
    }

    /**
     * 模型必须加 @RequestBody
     * 给群添加成员的接口(群总成员必须大于等于2)
     * @param groupId 群Id，你必须是这个群的管理者之一
     * @param model 添加成员的Model
     * @return  添加成员列表
     */
    @PostMapping("/{groupId}/member")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<List<GroupMemberCard>> memberAdd(@NotBlank @PathVariable("groupId") String groupId,
                                                          @RequestBody @Validated GroupMemberAddModel model){

        User self = userService.getUser();

        // 移除我后再进行数量判断
        model.getUsers().remove(self.getId());
        if (model.getUsers().size() == 0){
            return ResponseModel.error(CodeMsg.GROUP_ADD_MEMBER_LESS_THAN_TWO_ERROR);
        }

        // 判断群是否存在
        Group group = groupService.findById(groupId);
        if (group == null){
            return ResponseModel.error(CodeMsg.GROUP_NOT_FOUND_ERROR);
        }
        // 判断添加者是否 具有管理员权限+
        GroupMember member = groupMemberService.getMember(self, groupId);
        if (member == null || member.getPermissionType() == GroupMember.PERMISSION_TYPE_NONE){
            return ResponseModel.error(CodeMsg.GROUP_ADD_NOT_ADMINISTRATOR_ERROR);
        }

        // 获取群内成员列表
        Set<GroupMember> oldMembers = groupMemberService.getMembers(group);
        Set<String> oldMemberUserIds = oldMembers.stream()
                .map(GroupMember::getUserId)
                .collect(Collectors.toSet());

        // 群成员已在群内则跳过 否则加入群
        List<User> insertUsers = new ArrayList<>();
        for (String s : model.getUsers()) {
            // 找人
            User user = userService.findById(s);
            if (user == null)
                continue;
            // 已经在群里了
            if(oldMemberUserIds.contains(user.getId()))
                continue;
            insertUsers.add(user);
        }

        // 没有一个新增的成员
        if (insertUsers.size() == 0){
            return ResponseModel.error(CodeMsg.GROUP_ADD_NEW_MEMBER_LIST_EMPTY_ERROR);
        }

        // 数据库添加群成员
        Set<GroupMember> insertMembers = groupMemberService.addMembers(group, insertUsers);
        if (insertMembers == null){
            return ResponseModel.error(CodeMsg.ADD_GROUP_MEMBER_ERROR);
        }

        // Set 转 list
        List<GroupMemberCard> insertCards = insertMembers.stream()
                .map(GroupMemberCard::new)
                .collect(Collectors.toList());

        // 通知新增的成员，你被加入了XXX群
        pushService.pushJoinGroup(insertMembers);
        // 通知群中老的成员，有XXX，XXX加入群
        pushService.pushGroupMemberAdd(oldMembers, insertCards);
        return ResponseModel.success(insertCards);
    }


    /**
     *
     * 更改成员信息，请求的人要么是管理员，要么就是成员本人
     * @param memberId 成员Id，可以查询对应的群，和人
     * @param model
     * @return 当前成员的信息
     */
    @PutMapping("/member/{memberId}")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<GroupMemberCard> modifyMember(@PathVariable("memberId") String memberId, GroupMemberUpdateModel model){
        // todo
        return null;
    }

    /**
     * todo
     * 申请加入一个群
     * 此时会创建一个加入的申请，并写入表；然后会给管理员发送消息
     * 管理员同意，其实就是调用添加成员的接口把对应的用户添加进去
     * @param groupId groupId 群Id
     * @return 申请的信息
     */
    @PostMapping("/applyJoin/{groupId}")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<ApplyCard> join(@PathVariable("groupId") String groupId){
        // todo
        return null;
    }
}
